from django.db.models import Count

from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.exceptions import PermissionDenied

from django.conf import settings
from django.db import transaction
from django.forms.models import model_to_dict

from utils.generate import (
    create_bmi_and_whr,
    create_instance,
)
from utils.constants import (
    permission_deny_message
    # prj002_necessary_info, prj003_necessary_info,
    # prj002_necessary_cure, prj003_necessary_cure, prj004_necessary_info,
    # prj004_necessary_cure,
)
from celery_tasks.tasks import celery_save_data

from prj003.models import (
    summary, history, results,
    relevant, clinical, cure,
)
import prj002
import prj004
import prj005


# 权限设置: 审核通过的记录 此条信息无法修改(即使是审核人)
def deny_check(before_status, user, after_status, info_user, project_name):
    # 用户权限:
    # 1. 只能在('已提交', '未提交')之间状态转换
    # 2. '已提交' 的信息无法修改
    # 3. '未提交'=> 状态下只可以信息所有者更改状态为 '已提交'
    CHECK_PERMISSIONS = ('审核通过', '审核不通过')
    if before_status == '审核通过':
        raise PermissionDenied({'detail': '审核通过的记录无法更改审核状态'})

    if project_name == 'prj002':
        user_perm = user.has_perm('prj002.prj002_other_permissions')
        check_perm = user.has_perm('prj002.prj002_all_permissions')
    elif project_name == 'prj003':
        user_perm = user.has_perm('prj003.prj003_other_permissions')
        check_perm = user.has_perm('prj003.prj003_all_permissions')
    elif project_name == 'prj004':
        user_perm = user.has_perm('prj004.prj004_other_permissions')
        check_perm = user.has_perm('prj004.prj004_all_permissions')
    elif project_name == 'prj005':
        user_perm = user.has_perm('prj005.prj005_other_permissions')
        check_perm = user.has_perm('prj005.prj005_all_permissions')

    if all([
        user_perm,
        not check_perm,
        not user.is_admin,
    ]):
        if after_status in CHECK_PERMISSIONS:
            raise PermissionDenied({'detail': '对不起, 您并没有该操作权限'})
    else:
        # 审核用户: 未提交的信息无法进行审核; 需所有者先修改为'已提交'状态
        if before_status == '未提交' and after_status in CHECK_PERMISSIONS:
            raise PermissionDenied({'detail': '对不起, 该信息未确认提交状态'})

    if user != info_user and after_status == '已提交':
        raise PermissionDenied({'detail': '对不起, 您没有提交此数据的权限'})

    if before_status == '已提交' and after_status == '未提交':
        raise PermissionDenied({'detail': '"已提交"的记录无法更改为"未提交"'})

    if before_status == CHECK_PERMISSIONS[1] and after_status == '未提交':
        raise PermissionDenied({'detail': '"审核不通过"数据需要进行提交'})


class SCChartView(object):
    """ 分析数据 echarts需要数据形式返回
    """

    def get(self, request, *args, **kwargs):
        response_data = {'data': dict()}

        choice = self.model_.CHECKED_CHOICE
        choice_name = [tuple_choice[0] for tuple_choice in choice]
        response_data['data']['checked_status'] = choice_name

        total_object = self.model_.objects.all()

        # pine
        response_data['data']['pine'] = []
        for name in choice_name:
            value = total_object.filter(check_status=name).count()

            response_data['data']['pine'].append({'name': name, 'value': value})

        # hospitals_list
        hospital_data = total_object.select_related('owner')\
            .values('owner__hospital')\
            .annotate(hs_count=Count('owner__hospital'))\
            .order_by('-hs_count')
        hospital_list = [dict_hospital.get('owner__hospital') for dict_hospital in hospital_data]
        response_data['data']['hospitals_list'] = hospital_list

        # bar
        response_data['data']['bar'] = []
        for name in choice_name:
            data = []
            for hp in hospital_list:
                count = total_object.filter(owner__hospital=hp, check_status=name).count()
                data.append(count)
            response_data['data']['bar'].append({'name': name, 'data': data})

        return Response(response_data)


class SCSerializer(serializers.HyperlinkedModelSerializer):
    create_time = serializers.DateTimeField(format=settings.DATETIME_FORMAT, read_only=True)

    def validate_info(self, value):
        owner = value.owner
        user = self.context['view'].request.user

        if owner != user:
            raise PermissionDenied(detail=permission_deny_message.get('exist_info'))
        return value

    def update(self, instance, validated_data):
        current_info = validated_data.get('info')
        if current_info and current_info != instance.info:
            raise PermissionDenied(detail=permission_deny_message.get('exist_info'))

        # 更新的字段
        try:
            prj_name = self.Meta.project_name
            serial = instance.info.serial
            if instance.info.check_status == '审核不通过':
                before_instance = model_to_dict(instance)
                try:
                    before_instance.pop('info')
                    before_instance.pop('owner')
                    validated_data.pop('info')
                except KeyError:
                    celery_save_data.delay(before_instance, validated_data, serial, project_name=prj_name)
                else:
                    celery_save_data.delay(before_instance, validated_data, serial, project_name=prj_name)
        except Exception:
            raise ValueError('记录更新字段错误')

        return super().update(instance, validated_data)


class ExtendsSerializer(object):

    def need_info(self):
        try:
            prj_name = self.Meta.project_name
        except Exception:
            raise ValueError('序列化器Meta中缺少project_name参数')

        if prj_name == 'prj002':
            # necessary_info = prj002_necessary_info
            # necessary_cure = prj002_necessary_cure
            model_list = [
                prj002.models.summary.Summary,
                prj002.models.standard.Standard,
                prj002.models.bxray.Bxray,
                prj002.models.clinical.Clinical,
                prj002.models.cure.Cure,
                prj002.models.disease.Disease,
                prj002.models.experiment.Experiment,
                prj002.models.history.History,
            ]

        elif prj_name == 'prj003':
            # necessary_info = prj003_necessary_info
            # necessary_cure = prj003_necessary_cure
            model_list = [
                summary.Summary, history.History, cure.Cure,
                relevant.Relevant, clinical.Clinical, results.Results
            ]
        elif prj_name == 'prj004':
            # necessary_info = prj004_necessary_info
            # necessary_cure = prj004_necessary_cure
            model_list = [
                prj004.models.clinical.Clinical,
                prj004.models.cure.Cure,
                prj004.models.history.History,
                prj004.models.relevant.Relevant,
                prj004.models.result.Result,
                prj004.models.summary.Summary
            ]
        elif prj_name == 'prj005':
            model_list = [
                prj005.models.clinical.Clinical,
                prj005.models.cure.Cure,
                prj005.models.history.History,
                prj005.models.relevant.Relevant,
                prj005.models.result.Result,
                prj005.models.summary.Summary
            ]

        else:
            raise ValueError('project_name参数错误')

        data = {
            # 'necessary_info': necessary_info,
            # 'necessary_cure': necessary_cure,
            'prj_name': prj_name,
            'model_list': model_list,
        }

        return data

    def create(self, validated_data):
        validated_data = create_instance(validated_data, self.Meta.model)

        with transaction.atomic():
            point = transaction.savepoint()

            instance = self.Meta.model.objects.create(**validated_data)

            data = self.need_info()
            prj_name = data.get('prj_name')
            model_list = data.get('model_list')

            if prj_name == 'prj002':
                instance = create_bmi_and_whr(instance)

            try:
                instance.save()
                # 直接创建其他关系表
                if not self.Meta.save_mobile:
                    data_ = {'info': instance, 'owner': instance.owner}
                    self.create_other_table(data_, instance, model_list)

            except Exception as e:
                transaction.savepoint_rollback(point)
                raise e

            transaction.savepoint_commit(point)
        return instance

    def update(self, instance, validated_data):
        owner = instance.owner

        user = self.context['view'].request.user

        if owner != user:
            raise PermissionDenied(detail=permission_deny_message.get('exist_info'))

        data = self.need_info()
        prj_name = data.get('prj_name')

        try:
            # 更新的字段
            serial = instance.serial
            if instance.check_status == '审核不通过':
                before_instance = model_to_dict(instance)

                before_instance.pop('owner')

                celery_save_data.delay(before_instance, validated_data, serial, project_name=prj_name)
        except Exception:
            raise ValueError('记录更新字段错误')

        for key, value in validated_data.items():
            if hasattr(instance, key):
                setattr(instance, key, value)

        if prj_name == 'prj002':
            instance = create_bmi_and_whr(instance)

        instance.save()
        return instance

    # 创建info表后, 创建其他一对一的表内容
    def create_other_table(self, data, info, model_list):
        model_list = model_list

        for model_ in model_list:
            try:
                model_.objects.get(info=info)
            except model_.DoesNotExist:
                try:
                    model_.objects.create(**data)
                except Exception:
                    raise ValueError('创建表错误')
            except Exception as e:
                raise ValueError('创建表错误 {}'.format(e))
            else:
                continue


# class ProjectCureSerializer(object):
#     """信息完善度
#     : 相当于重写了 create update 方法
#     """

#     def get_params(self, instance):
#         try:
#             prj_name = self.Meta.project_name
#         except Exception:
#             raise ValueError('序列化器Meta中缺少project_name参数')

#         # data = {
#         #     'prj_name': prj_name
#         # }

#         if prj_name == 'prj002':
#             data = create_degree_of_completion(instance.info, prj002_necessary_info, prj002_necessary_cure)
#         elif prj_name == 'prj003':
#             data = create_degree_of_completion(instance.info, prj003_necessary_info, prj003_necessary_cure)
#         elif prj_name == 'prj004':
#             data = create_degree_of_completion(instance.info, prj004_necessary_info, prj004_necessary_cure)
#         else:
#             raise ValueError('序列化器Meta中project_name参数不正确')

#         instance.info.degree_of_completion = data
#         instance.info.save()

#         return instance

#     def create(self, validate_data):
#         instance = super().create(validate_data)
#         return self.get_params(instance)

#     def update(self, instance, validate_data):
#         for key, value in validate_data.items():
#             if hasattr(instance, key):
#                 setattr(instance, key, value)

#         instance.save()

#         return self.get_params(instance)


def func_pop_none_value(data, require_key):
    validate_data = dict()
    for key in require_key:
        value = data.get(key)
        if not value:
            inner = dict()
        else:
            inner = {k: v for k, v in value.items() if v not in ('', None)}

        validate_data.update({key: inner})

    return validate_data
